package com.hulk.dryad.web.oauth2.basic.social;


import com.hulk.dryad.common.constant.SecurityConstants;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author lqx
 * @date 2018/1/9 手机号登录验证filter
 */
public class SocialAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private static final String SPRING_SECURITY_FORM_MOBILE_KEY = "code";

    @Getter
    @Setter
    private String codeParameter = SPRING_SECURITY_FORM_MOBILE_KEY;

    @Getter
    @Setter
    private boolean postOnly = true;


    @Getter
    @Setter
    private AuthenticationEntryPoint dryadAuthExceptionEntryPoint;

    public SocialAuthenticationFilter() {
        super(new AntPathRequestMatcher(SecurityConstants.SOCIAL_TOKEN_URL, "GET"));
    }

    @Override
    @SneakyThrows
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
        if (!request.getMethod().equals(HttpMethod.GET.name())) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        String code = obtainCode(request);
        if (code == null) {
            code = "";
        }
        code = code.trim();
        SocialAuthenticationToken socialAuthenticationToken = new SocialAuthenticationToken(code);
        setDetails(request, socialAuthenticationToken);
        Authentication authResult = null;
        try {
            AuthenticationManager authenticationManager = this.getAuthenticationManager();
            authResult = authenticationManager.authenticate(socialAuthenticationToken);
            SecurityContextHolder.getContext().setAuthentication(authResult);
        } catch (Exception failed) {
            SecurityContextHolder.clearContext();
            logger.error("Authentication request failed: ", failed);
            try {
				dryadAuthExceptionEntryPoint.commence(request, response,
                        new UsernameNotFoundException(failed.getMessage(), failed));
            } catch (Exception e) {
                logger.error("authenticationEntryPoint handle error", e);
            }
        }
        return authResult;
    }

    private String obtainCode(HttpServletRequest request) {
        return request.getParameter(codeParameter);
    }

    private void setDetails(HttpServletRequest request, SocialAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }

}
